
/*
 * This file use as utility to check the clustering is good or not for dataset KKCUP99
 * StreamKmean++ will be take into account first.
 * The result of StreamKmean++ algorithm is the list of centers point.
 * This utility will supply the function to labeling the is normal or abnormal
 * base on the percentage of each cluster. The assumption that the attack is maller than
 * the normal access.
 *
*/


#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <time.h>

#include "Point.h"
#include "mt19937ar.h"
#include "kMeansUtilityFunctions.h"
#include "DatasetFunctions.h"
#include "LloydPlusPlus.h"
#include "StreamingCoreset.h"

#define  DEBUG_FLAG 0

void loadCentersLiadanFormat(FILE* out, int numberOfCenters, struct point * centers,int dimension);
int getPointLabel(FILE* point_labeled_file, char* point_label, int lenght, int dimension);

int main(int argc, char * argv[])
{
	if(argc < 7)
	{
		printf("*************** Usage ********************\n\n");

		printf("%s centerFile  unlabledDatasetFile labeledDatasetFile kCluster length dimension \n", argv[0]);

		printf("******************************************\n");

		return 0;
	}

	FILE *centersFile         = fopen(argv[1],"r");
	FILE *dataset             = fopen(argv[2],"r");
	FILE *dataset_labeled     = fopen(argv[3],"r");

	/*Hard code!!!!!!!!!*/
	int numberOfCentres = atoi(argv[4]);
	int length          = atoi(argv[5]);
	int dimension       = atoi(argv[6]);



	// The array of number of points which belong to certain centers
	int* numOfPointInEachCenter = (int*) malloc (numberOfCentres * sizeof(int));
	memset(numOfPointInEachCenter, 0, numberOfCentres * sizeof(int));
	// the array of lable point
	char* point_labeled = (char*) malloc(length * sizeof(char));
	memset(point_labeled, 0, length * sizeof(char));

	/*Get the all centers which calculated by streamkm algorithm */
	struct point* centers = (point*) malloc( numberOfCentres * sizeof(struct point) );
	memset(centers, 0, numberOfCentres * sizeof(struct point) );

	// Init the memory for all dimension of one point
	for (int i = 0; i < numberOfCentres; i++)
	{
		initPoint( &centers[i], dimension);
	}

	loadCentersLiadanFormat(centersFile, numberOfCentres, centers, dimension);


	// Go through dataset file with the number of point is length
	for (int i = 0; i < length; i++)
	{
		struct point *p = (point *)malloc(sizeof(struct point));
		initPoint(p,dimension);
		getNextPointLiadan(dataset,p,dimension);

		int center_index = determineClusterCentreKMeans(numberOfCentres, *p, centers);
		if(center_index < 0 || center_index > numberOfCentres - 1)
		{
			printf("Not found the cluser which point is belong to \n");
		}
		else
		{
			numOfPointInEachCenter[center_index]++;
		}
		freePoint(p);
		free(p);
	}

	#if DEBUG_FLAG
	//Print the array of number of point
	for(int i = 0; i < numberOfCentres; i++)
	{
		printf("The number of point of center %d: %d \n", i, numOfPointInEachCenter[i]);
	}
	
	#endif

	// Calculate the index of normal cluster in center clusters
	int normal_index_cluster = numberOfCentres-1;
	for(int i = 0; i < numberOfCentres-1; i++)
	{
		if(numOfPointInEachCenter[i] > numOfPointInEachCenter[normal_index_cluster])
		{
			normal_index_cluster = i;
		}
	}
	printf("Normal cluster index: %d \n", normal_index_cluster);



	//calculate the ratio between the number of actual normal point and number of clustering normal point
	int actual_normal_point =  getPointLabel(dataset_labeled, point_labeled, length, dimension);
	float detection_rate    = 0.0f;
	detection_rate          = (float)numOfPointInEachCenter[normal_index_cluster] / (float)actual_normal_point;

	printf("The number of cluster k:          %d \n", numberOfCentres);
	printf("Actual normal point:              %d \n", actual_normal_point);
	printf("clustering normal point:          %d \n", numOfPointInEachCenter[normal_index_cluster]);
	printf("detection rate:                   %f \n", detection_rate);


	//Calculate the fail ratio of detection
	// move the begin of dataset.wsv file
	rewind(dataset);

	int failure_clus_count = 0;
	// Go through dataset file with the number of point is length
	for (int i = 0; i < length; i++)
	{
		struct point *p = (point *)malloc(sizeof(struct point));
		initPoint(p,dimension);
		getNextPointLiadan(dataset,p,dimension);

		int center_index = determineClusterCentreKMeans(numberOfCentres, *p, centers);
		if(center_index < 0 || center_index > numberOfCentres - 1)
		{
			printf("Not found the cluser which point is belong to \n");
		}
		else
		{
			// If the normal point is not correct clustering
			// There are two possibility can happen the first is normal point is clustered to
			// abnormal cluster, the second is the abnormal point is clustered to normal cluster

			// This first case
			if ( (center_index == normal_index_cluster && !point_labeled[i])
				 || (center_index != normal_index_cluster && point_labeled[i]))
			{
				failure_clus_count++;
			}
		}
		freePoint(p);
		free(p);
	}

	float failure_detection_rate   = (float)failure_clus_count / (float) length;
	printf("The failure detection count:              %d \n", failure_clus_count);
	printf("Failure detection rate:                   %f \n", failure_detection_rate);

}



/*
 *  loads the centers to a file with the separator ' ' and a the weight as the first row
 * */
void loadCentersLiadanFormat(FILE* input, int numberOfCenters, struct point * centers,int dimension){

	if (input)
	{
		for(int i=0;i<numberOfCenters;i++){
					int l;
					float temp = 0.0;
					centers[i].weight = readDouble(input);

					for(l=0;l<dimension-1;l++){
						temp = readDouble(input);
						centers[i].coordinates[l] =  temp * centers[i].weight;
					}
					temp = readDouble(input);
					centers[i].coordinates[dimension-1] = temp * centers[i].weight;
				}
	}
	else
	{
		printf("input is null");
	}
}


/*
 *
 *
 */
int getPointLabel(FILE* point_labeled_file, char* point_label, int lenght, int dimension)
{

	// The number of normal point
	int normal_point_num = 0;

	for(int i = 0; i < lenght; i ++)
	{
		//Read each point for labeled file
		char c='\0';

		// Skip dimension attributes
		int comma = 0;
		do
		{
			c = fgetc(point_labeled_file);
			if(c == ',')
			{
				comma++;
			}
		} while(comma < dimension);

		// Read the actual label
		static char buf[100];
		memset(buf, 0 , 100);
		int index = 1;
		while((c = fgetc(point_labeled_file)) ==' ' && c != EOF){}
		buf[0] = c;
		while((c = fgetc(point_labeled_file)) != '\n' && c != ' ' && c != EOF){
			buf[index++] = c;
		}
		buf[index]=0;

		if( !strcmp (buf, "normal.") )
		{
			point_label[i] = 1;
			normal_point_num++;
		}
	}

	return normal_point_num;
}

